package grammar;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import geometry.GeomMatch;
import geometry.Geometry;
import geometry.Transform;
import graph.GNode;
import graph.GraphMatch;

public class Match {
    private Design lhs;
    private Rule rule;
    private GraphMatch graphMatch;
    private Map<GNode, GeomMatch> nodeToGeomMatches = new HashMap<GNode, GeomMatch>(); 
    
    public Match(Rule rule, GraphMatch graphMatch) {
        this.graphMatch = graphMatch;
        this.rule = rule;
        this.lhs = rule.getLHS();
    }

    public void addGeomMatch(GNode node, GeomMatch geomMatch) {
        this.nodeToGeomMatches.put(node, geomMatch);
    }
    
    public String toString() {
        String s = "\nGRAPH MATCH-----------------------------";
        s=s.concat(graphMatch.toString());
        s=s.concat("\n\nGEOMETRY MATCH-----------------------------");
        for (GNode node : this.nodeToGeomMatches.keySet()) {
            s=s.concat("\nNode name-"+ node.getLabelsString()+ " "+node.getDebugId());
            GeomMatch geomMatch = this.nodeToGeomMatches.get(node);
            s=s.concat("\tNumber matches found for node = " + geomMatch.toString());
        }
        return s;
    }

    /**
     * returns the transformation assigned to this LHS Node
     * @param rhsNode
     */
    public Transform getTransformation(GNode node) {
        GeomMatch geomMatch = this.nodeToGeomMatches.get(node);
        if (geomMatch == null) {
            return null;
        }
        return geomMatch.getTransformation();
    }

    public boolean isComplete(int numberNodesMatched) {
        if (!graphMatch.isComplete(numberNodesMatched)) {
            return false;
        }
        for (GNode lhsNode : this.graphMatch.keyNodes()) {
            GeomMatch geomMatch = this.nodeToGeomMatches.get(lhsNode);
            if (lhsNode instanceof Geometry && geomMatch == null) {
                return false;
            }
        }
        return true;
    }

    public GNode getNextNodeforGeometricMatch() {
        for (GNode lhsNode : this.graphMatch.keyNodes()) {
            GeomMatch geomMatch = this.nodeToGeomMatches.get(lhsNode);
            if (lhsNode instanceof Geometry && geomMatch == null) {
                return lhsNode;
            }
        }
        return null;
    }

    public Match copy() {
        Match match = new Match(rule, graphMatch.copy());
        for (Entry<GNode, GeomMatch> entry : this.nodeToGeomMatches.entrySet()) {
            match.nodeToGeomMatches.put(entry.getKey(), entry.getValue());
        }
        return match;
    }

    public GNode getMatchedNode(GNode node) {
        return graphMatch.getToFindMatch(node);
    }
}
